package com.ecreditpal.audio.server;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.ecreditpal.audio.netty.config.NettyServerProperties;
import com.ecreditpal.audio.netty.handler.*;
import com.ecreditpal.audio.model.AudioModel;
import com.ecreditpal.audio.netty.message.CustomProtobufDecoder;
import com.ecreditpal.audio.netty.message.CustomProtobufEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.MediaType;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author lifeng
 * @version 1.0 on 2018/4/21.
 */
@EnableEurekaClient
//@EnableDiscoveryClient
@ComponentScan(basePackages = "com.ecreditpal.audio")
@SpringBootApplication
@Slf4j
public class Application implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, CommandLineRunner {

    @Value("${server.port}")
    private String port;

    @Autowired
    NettyServerProperties nettyServerProperties;

    public static void main(String[] args) {
        new SpringApplicationBuilder().sources(Application.class)
                .bannerMode(Banner.Mode.CONSOLE)
                .run(args);

    }


    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters(ApplicationContext ctx) {

        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();

        FastJsonConfig fastJsonConfig = new FastJsonConfig();

        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);

        fastConverter.setFastJsonConfig(fastJsonConfig);
        List<MediaType> list = new ArrayList<>();
        list.add(MediaType.APPLICATION_JSON_UTF8);
        fastConverter.setSupportedMediaTypes(list);

        return new HttpMessageConverters(fastConverter);
    }


    @Override
    public void customize(ConfigurableServletWebServerFactory configurableServletWebServerFactory) {
//        Integer port = ConfigurationManager.getConfiguration().getInt("server.port");
        configurableServletWebServerFactory.setPort(Integer.valueOf(port));
    }

    @Override
    public void run(String... strings) throws Exception {
        log.info("start ");
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();

            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 100)
//                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
//                            ch.pipeline().addLast(new ProtobufVarint32FrameDecoder());
//                            ch.pipeline().addLast(new ProtobufDecoder(AudioModel.Audio.getDefaultInstance()));
//                            ch.pipeline().addLast(new CustomPrepender());
//                            ch.pipeline().addLast(new ProtobufEncoder());
                            ch.pipeline().addLast("Decoder",new CustomProtobufDecoder(AudioModel.Audio.getDefaultInstance()));
                            ch.pipeline().addLast("IdleHandler",new IdleStateHandler(20, 0, 0, TimeUnit.SECONDS));
                            ch.pipeline().addLast("Encoder",new CustomProtobufEncoder());
                            ch.pipeline().addLast("RequestHandler",new SubReqServerHandler());
                            ch.pipeline().addLast("HeartBeatHandler",new HeartBeatRespHandler());
                        }
                    });

            ChannelFuture f = b.bind(nettyServerProperties.getPort()).sync();
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }



}
